
`ifndef FLOAT_SIM_PKG_SVH
`define FLOAT_SIM_PKG_SVH

`include "float_arith_pkg.svh"

package float_sim;

   import float_arith::*;
   
   function automatic string roundmode2str(input logic [1:0] rounding_mode);
      string 					       str;
      case(rounding_mode)
	2'd0:
	  return "round_nearest_even";
	2'd1:
	  return "round_down";
	2'd2:
	  return "round_up";
	2'd3:
	  return "round_to_zero";
	default:
	  return "unknown rounding mode";
      endcase
   endfunction // roundmode2str
   
   
   function automatic string exception2str( input excp_t excp );			// FIXME: not hard-wired !!!!!
      string 					       str = "";
   logic       invalid;
   logic       divbyzero;
   logic       overflow;
   logic       underflow;
   logic       inexact;

      
      if(excp.invalid)
	str = {str, "Invalid "};
      if(excp.divbyzero)
	str = {str, "DivByZero "};
      if(excp.overflow)
	str = {str, "Overflow "};
      if(excp.underflow)
	str = {str, "Underflow "};
      if(excp.inexact)
	str = {str, "Inexact "};

      if(str == "")
	return "no exception";
      else
	return str.substr(0,str.len()-2);

   endfunction // exception2str

   
   function automatic string float32_to_fieldstr(input float32_t a);
      string str;
      $sformat(str, "%d.%02x.%06x", a.sign, a.exp, a.sig);
      return str;
   endfunction
   
   
   
   function automatic string float32_to_str(input float32_t a);
      string str = "";
      
      if($isunknown(a))
	begin
	   $sformat(str, "%x", a);
	   return str;
	end

      if(a.exp === 8'hff)
	begin
	   if(a.sig === '0)	// INF
	     begin
		$sformat(str, "%sINF", a.sign ? "-" : "+");
	     end
	   else			// NaN
	     begin
		if(a.sig[22])
		  $sformat(str, "QNaN");
		else
		  $sformat(str, "SNaN");
	     end // else: !if(a.sig === '0)
	end // if (a.exp === 8'hff)
      else
	begin
	   int true_exp = a.exp-127;
	   int frac = a.sig;
	   real f;
	   
	   if(a.exp)
	     frac |= 32'h800000; // the hidden '1' for normal
	   else
	     true_exp++;	// true_exp is -126 for subnormal

	   true_exp -= 23;

	   if(true_exp >= 0)
	     f = frac * (2.0**true_exp);
	   else
	     f = frac / (2.0**-true_exp);

	   // if(a.sign)
	   //   f = -f;
	   
	   $sformat(str, "%s%g", (a.sign ? "-" : "+"), f);
	end // else: !if(a.exp === 8'hff)
      return str;

   endfunction // float32_to_str
   

   function automatic print_float32(input float32_t a);
      shortreal r = 3.14e11;
      $display("%x (%d.%x.%x %f)", a, a.sign, a.exp, a.sig, r);

      
   endfunction // print_float32


   
   function automatic string float64_to_fieldstr(input float64_t a);
      string str;
      $sformat(str, "%d.%03x.%013x", a.sign, a.exp, a.sig);
      return str;
   endfunction
   
   function automatic string float64_to_str(input float64_t a);
      string str = "";
      
      if($isunknown(a))
	begin
	   $sformat(str, "%x", a);
	   return str;
	end

      if(a.exp === 11'h7ff)
	begin
	   if(a.sig === '0)	// INF
	     begin
		$sformat(str, "%sINF", a.sign ? "-" : "+");
	     end
	   else			// NaN
	     begin
		if(a.sig[51])
		  $sformat(str, "QNaN");
		else
		  $sformat(str, "SNaN");
	     end // else: !if(a.sig === '0)
	end // if (a.exp === 8'hff)
      else
	begin
	   int true_exp = a.exp-1023;
	   longint frac = a.sig;
	   real f;
	   
	   if(a.exp)
	     frac |= 64'h10_0000_0000_0000; // the hidden '1' for normal
	   else
	     true_exp++;	// true_exp is -1022 for subnormal

	   true_exp -= 52;

	   if(true_exp >= 0)
	     f = frac * (2.0**true_exp);
	   else
	     f = frac / (2.0**-true_exp);

	   // if(a.sign)
	   //   f = -f;
	   
	   $sformat(str, "%s%g", (a.sign ? "-" : "+"), f);
	end // else: !if(a.exp === 8'hff)
      return str;

   endfunction // float64_to_str
   

   function automatic print_float64(input float64_t a);
      shortreal r = 3.14e11;
      $display("%x (%d.%x.%x %f)", a, a.sign, a.exp, a.sig, r);
   endfunction // print_float64

endpackage


`endif /* FLOAT_SIM_PKG_SVH */

